package com.yjd.comm.logs;

import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.util.Calendar;
import java.util.Date;

import org.apache.log4j.RollingFileAppender;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;

import com.yjd.comm.util.DateUtil;
import com.yjd.comm.util.FrameUtil;

/**
 * <b>description</b>：log4j日志 <br>
 * <b>time</b>：2015-3-24下午3:00:30 <br>
 * <b>author</b>： ready likun_557@163.com
 */
public class RollingFileAppenderWrap extends RollingFileAppender {

	/**
	 * 原文文件名称
	 */
	protected String orgFilename;
	/**
	 * 当前文件开始时间
	 */
	protected Date starttime;

	/**
	 * 当前文件结束日期
	 */
	protected Date endtime;

	/**
	 * 文件后缀
	 */
	private static final String FILE_STUFF = ".log";
	/**
	 * 文件时间格式
	 */
	private String DATE_FORMAT = "yyyyMMddHHmm";

	public long getNextRollover() {
		Long value = 0l;
		try {
			value = FrameUtil.getField(this, "nextRollover");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}

	public void setNextRollover(long nextRollover) {
		try {
			FrameUtil.setField(this, "nextRollover", nextRollover);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void rollOver() {
		this.endtime = Calendar.getInstance().getTime();
		String targetFm = getEndFileName();
		File target;
		File file;

		if (qw != null) {
			long size = ((CountingQuietWriter) qw).getCount();
			LogLog.debug("rolling over count=" + size);
			// if operation fails, do not roll again until
			// maxFileSize more bytes are written
			this.setNextRollover(size + maxFileSize);
		}
		LogLog.debug("maxBackupIndex=" + maxBackupIndex);

		boolean renameSucceeded = true;
		// If maxBackups <= 0, then there is no file renaming to be done.
		if (maxBackupIndex > 0) {
			// Delete the oldest file, to keep Windows happy.
			file = new File(targetFm + '.' + maxBackupIndex + FILE_STUFF);
			if (file.exists())
				renameSucceeded = file.delete();

			// Map {(maxBackupIndex - 1), ..., 2, 1} to {maxBackupIndex, ..., 3,
			// 2}
			for (int i = maxBackupIndex - 1; i >= 1 && renameSucceeded; i--) {
				file = new File(targetFm + "." + i + FILE_STUFF);
				if (file.exists()) {
					target = new File(targetFm + '.' + (i + 1) + FILE_STUFF);
					LogLog.debug("Renaming file " + file + " to " + target);
					renameSucceeded = file.renameTo(target);
				}
			}

			if (renameSucceeded) {
				// Rename fileName to fileName.1
				target = new File(targetFm + "." + 1 + FILE_STUFF);

				this.closeFile(); // keep windows happy.

				file = new File(fileName);
				LogLog.debug("Renaming file " + file + " to " + target);
				renameSucceeded = file.renameTo(target);
				//
				// if file rename failed, reopen file with append = true
				//
				if (!renameSucceeded) {
					try {
						this.setFile(fileName, true, bufferedIO, bufferSize);
					} catch (IOException e) {
						e.printStackTrace();
						if (e instanceof InterruptedIOException) {
							Thread.currentThread().interrupt();
						}
						LogLog.error("setFile(" + fileName
								+ ", true) call failed.", e);
					}
				}
			}
		}

		//
		// if all renames were successful, then
		//
		if (renameSucceeded) {
			try {
				// This will also close the file. This is OK since multiple
				// close operations are safe.
				this.newFile();
				this.setFile(fileName, false, bufferedIO, bufferSize);
				this.setNextRollover(0);
			} catch (IOException e) {
				e.printStackTrace();
				if (e instanceof InterruptedIOException) {
					Thread.currentThread().interrupt();
				}
				LogLog.error("setFile(" + fileName + ", false) call failed.", e);
			}
		}
	}

	@Override
	public void setFile(String file) {
		super.setFile(file);
		this.orgFilename = this.fileName;
		this.newFile();
	}

	public void newFile() {
		this.starttime = Calendar.getInstance().getTime();
		this.fileName = this.orgFilename + FILE_STUFF;
	}

	public String getEndFileName() {
		this.endtime = Calendar.getInstance().getTime();
		return this.orgFilename + "_"
				+ DateUtil.format(this.starttime, DATE_FORMAT) + "-"
				+ DateUtil.format(this.endtime, DATE_FORMAT);
	}

}
